package yzx.fileutil.util;

import android.os.Environment;
import android.os.Handler;
import android.os.Looper;

import java.io.File;
import java.io.FileFilter;
import java.util.LinkedList;
import java.util.List;

public class BigFileScanner {

        private final int MAX = 1024*1024*10;
        private boolean hasStarted = false;
        private final StopTag stopTag = new StopTag();


        /** start 扫描 */
        public void startScan(final OnProgressListener onProgressListener){
            if(hasStarted) throw new IllegalStateException("task has started, use new");
            hasStarted = true;
            final LinkedList<File> dirList = getScanDirs();
            new Thread(new Runnable() {
                public void run() {
                    final LinkedList<File> resultList=new LinkedList<>();
                    for (File dir : dirList) {
                        if(!stopTag.running) return ;
                        scanSingleDir(dir, new OnProgressListener() {
                            public void onComplete(List<File> list) {
                                resultList.addAll(list);
                            }
                            public void onFileFound(File file) {
                                onProgressListener.onFileFound(file);
                            }
                        });
                    }
                    if(!stopTag.running)
                        return ;
                    new Handler(Looper.myLooper()).post(new Runnable() {
                        public void run() {
                            onProgressListener.onComplete(resultList);
                        }
                    });
                }
            }).start();
        }


        /** stop scan */
        public void stop(){
            stopTag.running = false;
        }


        /* 准备扫描的文件夹 */
        private LinkedList<File> getScanDirs(){
            LinkedList<File> dirList = new LinkedList<>();
            dirList.add(Environment.getExternalStorageDirectory());
            return dirList;
        }
        /* scan one dir */
        private void scanSingleDir(File dir, final OnProgressListener listener){
            final LinkedList<File> resultList = new LinkedList<>();
            fileIterator(dir, new IteratorFileListener() {
                public void onIterator(File file) {
                    resultList.add(file);
                    listener.onFileFound(file);
                }
            }, new FileFilter() {
                public boolean accept(File file) {
                    if(file.isDirectory()){
                        try{
                            return true;
                        }catch (Exception e){
                            return false;
                        }
                    }else
                        return file.length()>MAX;
                }
            }, stopTag);
            if(stopTag.running)
                listener.onComplete(resultList);
        }



  /*==============================================*/


        public interface OnProgressListener{
            void onComplete(List<File> list);
            void onFileFound(File file);
        }

        private interface IteratorFileListener{
            void onIterator(File file);
        }
        private static class StopTag{
            volatile boolean running = true;
        }


        /** scan file with the given dir */
        public static void fileIterator(File baseDir, BigFileScanner.IteratorFileListener listener, FileFilter fileFilter, BigFileScanner.StopTag st){
            LinkedList<File> readyAnalysisList = new LinkedList<>();
            readyAnalysisList.add(baseDir);
            if(fileFilter==null) fileFilter = new FileFilter() {
                public boolean accept(File pathname) {return true;}
            };
            out:while(!readyAnalysisList.isEmpty()){
                if(!st.running) break;
                File analysisDir = readyAnalysisList.removeFirst();
                File[] childFiles = analysisDir.listFiles();
                if(childFiles == null || childFiles.length == 0)
                    continue;
                for (File childFile : childFiles) {
                    if(!st.running) break out;
                    if(!fileFilter.accept(childFile))
                        continue ;
                    if(childFile.isDirectory()) {
                        readyAnalysisList.add(childFile);
                    }else
                        listener.onIterator(childFile);
                }
            }
        }

}
